import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static int[][] arr = new int[110][110];
    public static int[][] dp = new int[110][110];//记录长度
    public static int[] dx={0,0,1,-1};
    public static int[] dy={1,-1,0,0};
    public static int M;
    public static int N;
    public static int dfs(int i,int j){
        if(dp[i][j]!=0) return dp[i][j];
        int len =1;
        for(int k=0;k<4;k++){
            int x = i+dx[k];
            int y = j+dy[k];
            if(x>=0 && x<N && y>=0 && y<M && arr[i][j]>arr[x][y]){
                len = Math.max(len,dfs(x,y)+1);
            }
        }
        dp[i][j] = len;
        return len;
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        N = in.nextInt();//宽
        M = in.nextInt();//长
        for(int i =0;i<N;i++){
            for(int j = 0;j<M;j++){
                arr[i][j] = in.nextInt();
            }
        }
        int ret = 0;
        for(int i = 0;i<N;i++){
            for(int j = 0;j<M;j++){
                ret = Math.max(ret,dfs(i,j));
            }
        }
        System.out.println(ret);
    }

    public static void main2(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        double ret = 1;
        long sum1 = 1;
        long sum2 = 1;
        int k = n-m+1,j=2;
        while(k<=n||j<=m){
            if(k<=n&&j<=m){
                ret = ret*k/j;
            }else if(k<=n&&j>m){
                ret = ret*k;
            }else{
                ret = ret/j;
            }
            k++;j++;
        }
        double sum3 = 1;
        for(int i =0;i<m;i++){
            sum3*=0.8;
        }
        double sum4 = 1;
        for(int i = 0;i<n-m;i++){
            sum4*=0.2;
        }
        ret = ret*sum3*sum4;
        System.out.printf("%.4f",ret);
    }

    //找无重复字符的最长子串
    public int lengthOfLongestSubstring(String s) {
        char[] ss = s.toCharArray();
        int n = ss.length;
        int left = 0;
        int right = 0;
        int ret = 0;
        int[] hash = new int[128];
        while(right<n){
            //进窗口
            char in = ss[right];
            hash[in]++;
            //判断是否出窗口
            while(hash[in]>1){
                char out = ss[left];
                hash[out]--;
                left++;
            }
            ret = Math.max(ret,right-left+1);
            right++;
        }
        return ret;
    }

    //最大平均数和最小平均数
    public static void main3(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        double[] nums = new double[n-m];
        for(int i = 0 ;i<n-m;i++){
            nums[i] = in.nextInt();
        }

        double ret1 = 0;//最大可能
        double ret2 = 0;//最小可能

        for(int i = 0;i<n-m;i++){
            ret2 += nums[i]/n;
        }

        ret1 = ret2;

        double one = 1;
        double five = 5;
        for(int i =0;i<m;i++){
            ret2 += one/n;
        }
        for(int i = 0;i<m;i++){
            ret1 += five/n;
        }

        System.out.printf("%.5f %.5f",ret2,ret1);
    }
    //栈和排序
    public int[] solve (int[] a) {
        Stack<Integer> stack = new Stack<>();
        int n = a.length;
        int j = 0;
        int[] ret = new int[n];
        int aim = n;//记录数组a中的最大值
        boolean[] hash = new boolean[n+1];//记录栈中存在的元素

        for(int i = 0;i<n;i++){
            //依次进栈
            stack.push(a[i]);
            hash[a[i]] = true;
            //更新aim
            while(hash[aim]){
                aim--;
            }
            while(!stack.isEmpty()&&stack.peek()>=aim){
                //出栈
                ret[j++] = stack.peek();
                stack.pop();
            }
        }

        return ret;
    }
    //长度最小的子数组
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int right = 0;
        int ret = Integer.MAX_VALUE;
        int sum = 0;
        while(right<nums.length){
            //进窗口
            sum+=nums[right];
            while(left<=right&&sum>=target){
                ret = Math.min(ret,right-left+1);//更新结果
                //出窗口
                sum-=nums[left];
                left++;
            }
            right++;
        }
        return ret==Integer.MAX_VALUE?0:ret;
    }

    public int lengthOfLongestSubstring1(String s) {
        char[] ss = s.toCharArray();
        int n = ss.length;
        int left = 0;
        int right = 0;
        int ret = 0;
        int[] hash = new int[128];
        while(right<n){
            //进窗口
            char in = ss[right];
            hash[in]++;
            //判断是否出窗口
            while(hash[in]>1){
                char out = ss[left];
                hash[out]--;
                left++;
            }
            ret = Math.max(ret,right-left+1);
            right++;
        }
        return ret;
    }

    //最大连续1的子串个数
    public int longestOnes(int[] nums, int k) {
        int ret = 0;
        for(int left = 0,right = 0,zero = 0;right<nums.length;right++){
            if(nums[right]==0) zero++;
            while(zero>k)
                if(nums[left++] == 0) zero--;
            ret = Math.max(ret,right-left+1);
        }
        return ret;
    }
    //将x减到0的最小操作数 （滑动窗口）
    public int minOperations(int[] nums, int x) {
        int sum = 0;
        for(int num:nums){
            sum+=num;
        }
        int target = sum - x;
        if(target<0) return -1;
        int ret = -1;
        for(int left = 0,right = 0,tmp=0;right<nums.length;right++){
            //进窗口
            tmp+=nums[right];
            //判断是否出窗口
            while(tmp>target){
                tmp-=nums[left];
                left++;
            }
            //更新结果
            if(tmp == target) ret = Math.max(ret,right-left+1);
        }
        return ret==-1?-1:nums.length-ret;
    }
}
